package winsvc

import (
	"fmt"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"

	"github.com/sirupsen/logrus"
	"golang.org/x/sys/windows/svc"
)

type Service interface {
	RunApplication() error
	Install()
	Uninstall()
	Start()
	Stop()
	Restart()
	IsServiceExist() bool
	GetServiceStatus() (State, error)
	MessageBox(caption, text string, style uint32) int
}

type serviceImpl struct {
	config   *Config
	logger   *logrus.Logger
	stopFlag bool
}

func NewService(config *Config) Service {
	return &serviceImpl{
		config:   config,
		logger:   GetLogger(),
		stopFlag: false,
	}
}

func (s *serviceImpl) Execute(_ []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (ssec bool, errno uint32) {
	const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown
	changes <- svc.Status{State: svc.StartPending}
	var wg sync.WaitGroup
	stopCh := make(chan struct{})
	wg.Add(1)
	go func() {
		s.handleRunAsApplication(stopCh, &wg)
	}()

	s.logger.Info("服务已启动")

	changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
	for c := range r {
		switch c.Cmd {
		case svc.Stop, svc.Shutdown:
			s.stopFlag = true
			s.logger.Info("收到停止服务命令")
			changes <- svc.Status{State: svc.StopPending}
			// 关闭stopCh通道，通知应用程序停止
			close(stopCh)
			// 等待应用程序退出
			s.logger.Info("等待应用程序退出...")
			wg.Wait()
			s.logger.Info("应用程序已退出")
			return
		default:
			s.logger.Warning("无法识别命令: " + fmt.Sprint(c.Cmd))
		}
	}
	return
}

func (s *serviceImpl) RunApplication() error {
	isWinServ, err := svc.IsWindowsService()
	if err != nil {
		return fmt.Errorf("无法确定我们是否作为 Windows 服务运行: " + err.Error())
	}

	// 如果是Windows服务，则运行服务
	if isWinServ {
		return s.handleRunAsService()
	}

	// 如果不是Windows服务，则运行应用程序
	var wg sync.WaitGroup
	stopCh := make(chan struct{})
	wg.Add(1)
	go func() {
		s.handleRunAsApplication(stopCh, &wg)
	}()

	wg.Wait()
	s.logger.Info("退出")
	return nil
}

func (s *serviceImpl) handleRunAsService() error {
	s.logger.Info("服务启动中...")
	if err := svc.Run(s.config.ServiceName, s); err != nil {
		return fmt.Errorf("启动服务失败: " + err.Error())
	}
	s.logger.Info("服务正常退出。")
	return nil
}

func (s *serviceImpl) handleRunAsApplication(stopCh chan struct{}, wg *sync.WaitGroup) {
	defer wg.Done()

	// 创建系统信号通道，仅在非服务模式下使用
	stopSignal := make(chan os.Signal, 1)
	signal.Notify(stopSignal, syscall.SIGTERM, syscall.SIGINT)

	// 启动应用程序
	go func() {
		s.config.StartOn()
	}()

	// 创建定时器,每秒执行一次
	ticker := time.NewTicker(1 * time.Second)
	defer ticker.Stop()

	for {
		select {
		case <-stopCh:
			// 收到停止信号
			s.logger.Info("正在停止应用")
			// 执行停止回调
			s.config.StopOn()
			s.logger.Info("应用已停止")
			return
		case <-stopSignal:
			// 收到系统信号（仅在非服务模式下）
			isWinServ, _ := svc.IsWindowsService()
			if !isWinServ {
				s.logger.Info("收到系统停止信号")
				s.config.StopOn()
				s.logger.Info("应用已停止")
				return
			}
		case <-ticker.C:
			// 定时执行业务逻辑
			s.logger.Debug("应用正在运行")
		}
	}
}
